1 module range_primitives_helper; 2 3 import std.algorithm.iteration : map, filter, joiner; 4 import std.algorithm.searching : any; 5 import std.conv : to; 6 import std.array; 7 import std.range; 8 import std.traits; 9 10 @safe: 11 12 /** 13 * This function produces a descriptive message why `R` is not an InputRange. 14 * If `R` is an InputRange the returned string will say so. 15 */ 16 string isInputRangeErrorFormatter(R)() pure { 17 static if(is(typeof(R.init) == R)) { 18 string ret = R.stringof ~ " is not an InputRange because:\n\t"; 19 20 Test[] tests = 21 [ isValidEmpty!R() 22 , isFrontValid!R() 23 , isPopFrontValid!R() 24 ]; 25 26 auto msg = testsToString(tests); 27 28 bool failed = tests.map!(t => t.failed).any(); 29 30 return failed 31 ? ret ~ msg 32 : R.stringof ~ " is an InputRange"; 33 } else { 34 return R.stringof ~ " can not be tested as " ~ R.stringof ~ ".init" 35 ~ " does not construct a compileable " ~ R.stringof; 36 } 37 } 38 39 /// ditto 40 unittest { 41 struct Foo {} 42 enum msg = isInputRangeErrorFormatter!(Foo); 43 enum exp =`Foo is not an InputRange because: 44 the property 'empty' does not exist 45 and the property 'front' does not exist 46 and the function 'popFront' does not exist`; 47 static assert(msg == exp, msg ~ "\n" ~ exp); 48 string msg2 = isInputRangeErrorFormatter!(Foo); 49 assert(msg2 == exp, msg ~ "\n" ~ exp); 50 } 51 52 /// ditto 53 unittest { 54 struct Foo { 55 int empty; 56 } 57 enum msg = isInputRangeErrorFormatter!(Foo); 58 enum exp =`Foo is not an InputRange because: 59 the property 'empty' is not of type 'bool' but 'int' 60 and the property 'front' does not exist 61 and the function 'popFront' does not exist`; 62 static assert(msg == exp, msg ~ "\n" ~ exp); 63 string msg2 = isInputRangeErrorFormatter!(Foo); 64 assert(msg2 == exp, msg ~ "\n" ~ exp); 65 } 66 67 /// ditto 68 unittest { 69 struct Foo { 70 bool empty; 71 void front(); 72 } 73 enum msg = isInputRangeErrorFormatter!(Foo); 74 enum exp =`Foo is not an InputRange because: 75 the property 'front' does not return a non 'void' value 76 and the function 'popFront' does not exist`; 77 static assert(msg == exp, msg ~ "\n" ~ exp); 78 string msg2 = isInputRangeErrorFormatter!(Foo); 79 assert(msg2 == exp, msg ~ "\n" ~ exp); 80 } 81 82 /// ditto 83 unittest { 84 struct Foo { 85 bool empty; 86 int front(); 87 } 88 enum msg = isInputRangeErrorFormatter!(Foo); 89 enum exp =`Foo is not an InputRange because: 90 the function 'popFront' does not exist`; 91 static assert(msg == exp, msg ~ "\n" ~ exp); 92 string msg2 = isInputRangeErrorFormatter!(Foo); 93 assert(msg2 == exp, msg ~ "\n" ~ exp); 94 } 95 96 /// ditto 97 unittest { 98 struct Foo { 99 bool empty; 100 int front(); 101 void popFront(); 102 } 103 enum msg = isInputRangeErrorFormatter!(Foo); 104 enum exp =`Foo is an InputRange`; 105 static assert(msg == exp, msg ~ "\n" ~ exp); 106 string msg2 = isInputRangeErrorFormatter!(Foo); 107 assert(msg2 == exp, msg ~ "\n" ~ exp); 108 } 109 110 /** 111 * This function produces a descriptive message why `R` is not a ForwardRange. 112 * If `R` is an ForwardRange the returned string will say so. 113 */ 114 string isForwardRangeErrorFormatter(R)() pure { 115 static if(is(typeof(R.init) == R)) { 116 string ret = R.stringof ~ " is not an ForwardRange because\n\t"; 117 118 Test[] tests = 119 [ isValidEmpty!R() 120 , isFrontValid!R() 121 , isPopFrontValid!R() 122 , isSaveValid!R() 123 ]; 124 auto msg = testsToString(tests); 125 126 bool failed = tests.map!(t => t.failed).any(); 127 128 return failed 129 ? ret ~ msg 130 : R.stringof ~ " is an ForwardRange"; 131 } else { 132 return R.stringof ~ " can not be tested as " ~ R.stringof ~ ".init" 133 ~ " does not construct a compileable " ~ R.stringof; 134 } 135 } 136 137 /// ditto 138 unittest { 139 struct Foo {} 140 enum msg = isForwardRangeErrorFormatter!(Foo); 141 enum exp =`Foo is not an ForwardRange because 142 the property 'empty' does not exist 143 and the property 'front' does not exist 144 and the function 'popFront' does not exist 145 and the property 'save' does not exist`; 146 static assert(msg == exp, msg ~ "\n" ~ exp); 147 string msg2 = isForwardRangeErrorFormatter!(Foo); 148 assert(msg2 == exp, msg ~ "\n" ~ exp); 149 } 150 151 /// ditto 152 unittest { 153 struct Foo { 154 int empty; 155 } 156 enum msg = isForwardRangeErrorFormatter!(Foo); 157 enum exp =`Foo is not an ForwardRange because 158 the property 'empty' is not of type 'bool' but 'int' 159 and the property 'front' does not exist 160 and the function 'popFront' does not exist 161 and the property 'save' does not exist`; 162 static assert(msg == exp, msg ~ "\n" ~ exp); 163 string msg2 = isForwardRangeErrorFormatter!(Foo); 164 assert(msg2 == exp, msg ~ "\n" ~ exp); 165 } 166 167 /// ditto 168 unittest { 169 struct Foo { 170 bool empty; 171 void front(); 172 } 173 enum msg = isForwardRangeErrorFormatter!(Foo); 174 enum exp =`Foo is not an ForwardRange because 175 the property 'front' does not return a non 'void' value 176 and the function 'popFront' does not exist 177 and the property 'save' does not exist`; 178 static assert(msg == exp, msg ~ "\n" ~ exp); 179 string msg2 = isForwardRangeErrorFormatter!(Foo); 180 assert(msg2 == exp, msg ~ "\n" ~ exp); 181 } 182 183 /// ditto 184 unittest { 185 struct Foo { 186 bool empty; 187 int front(); 188 } 189 enum msg = isForwardRangeErrorFormatter!(Foo); 190 enum exp =`Foo is not an ForwardRange because 191 the function 'popFront' does not exist 192 and the property 'save' does not exist`; 193 static assert(msg == exp, msg ~ "\n" ~ exp); 194 string msg2 = isForwardRangeErrorFormatter!(Foo); 195 assert(msg2 == exp, msg ~ "\n" ~ exp); 196 } 197 198 /// ditto 199 unittest { 200 struct Foo { 201 bool empty; 202 int front(); 203 void popFront(); 204 } 205 enum msg = isForwardRangeErrorFormatter!(Foo); 206 enum exp =`Foo is not an ForwardRange because 207 the property 'save' does not exist`; 208 static assert(msg == exp, msg ~ "\n" ~ exp); 209 string msg2 = isForwardRangeErrorFormatter!(Foo); 210 assert(msg2 == exp, msg ~ "\n" ~ exp); 211 } 212 213 /// ditto 214 unittest { 215 struct Foo { 216 bool empty; 217 int front(); 218 void popFront(); 219 int save; 220 } 221 enum msg = isForwardRangeErrorFormatter!(Foo); 222 enum exp =`Foo is not an ForwardRange because 223 the property 'save' does not return a 'Foo' but a 'int'`; 224 static assert(msg == exp, msg ~ "\n" ~ exp); 225 string msg2 = isForwardRangeErrorFormatter!(Foo); 226 assert(msg2 == exp, msg ~ "\n" ~ exp); 227 } 228 229 /// ditto 230 unittest { 231 struct Foo { 232 bool empty; 233 int front(); 234 void popFront(); 235 Foo save() { return this; } 236 } 237 enum msg = isForwardRangeErrorFormatter!(Foo); 238 enum exp =`Foo is an ForwardRange`; 239 static assert(msg == exp, msg ~ "\n" ~ exp); 240 string msg2 = isForwardRangeErrorFormatter!(Foo); 241 assert(msg2 == exp, msg ~ "\n" ~ exp); 242 } 243 244 /** 245 * This function produces a descriptive message why `R` is not an BidirectionalRange. 246 * If `R` is an BidirectionalRange the returned string will say so. 247 */ 248 string isBidirectionalRangeErrorFormatter(R)() pure { 249 static if(is(typeof(R.init) == R)) { 250 string ret = R.stringof ~ " is not an BidirectionalRange because\n\t"; 251 252 Test[] tests = 253 [ isValidEmpty!R() 254 , isFrontValid!R() 255 , isPopFrontValid!R() 256 , isBackValid!R() 257 , isPopBackValid!R() 258 ]; 259 auto msg = testsToString(tests); 260 261 bool failed = tests.map!(t => t.failed).any(); 262 263 return failed 264 ? ret ~ msg 265 : R.stringof ~ " is an BidirectionalRange"; 266 } else { 267 return R.stringof ~ " can not be tested as " ~ R.stringof ~ ".init" 268 ~ " does not construct a compileable " ~ R.stringof; 269 } 270 } 271 272 /// ditto 273 unittest { 274 struct Foo {} 275 enum msg = isBidirectionalRangeErrorFormatter!(Foo); 276 enum exp =`Foo is not an BidirectionalRange because 277 the property 'empty' does not exist 278 and the property 'front' does not exist 279 and the function 'popFront' does not exist 280 and the property 'back' does not exist 281 and the function 'popBack' does not exist`; 282 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 283 string msg2 = isBidirectionalRangeErrorFormatter!(Foo); 284 assert(msg2 == exp, msg ~ "\n" ~ exp); 285 } 286 287 /// ditto 288 unittest { 289 struct Foo { 290 int empty; 291 } 292 enum msg = isBidirectionalRangeErrorFormatter!(Foo); 293 enum exp =`Foo is not an BidirectionalRange because 294 the property 'empty' is not of type 'bool' but 'int' 295 and the property 'front' does not exist 296 and the function 'popFront' does not exist 297 and the property 'back' does not exist 298 and the function 'popBack' does not exist`; 299 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 300 string msg2 = isBidirectionalRangeErrorFormatter!(Foo); 301 assert(msg2 == exp, msg ~ "\n" ~ exp); 302 } 303 304 /// ditto 305 unittest { 306 struct Foo { 307 bool empty; 308 void front(); 309 } 310 enum msg = isBidirectionalRangeErrorFormatter!(Foo); 311 enum exp =`Foo is not an BidirectionalRange because 312 the property 'front' does not return a non 'void' value 313 and the function 'popFront' does not exist 314 and the property 'back' does not exist 315 and the function 'popBack' does not exist`; 316 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 317 string msg2 = isBidirectionalRangeErrorFormatter!(Foo); 318 assert(msg2 == exp, msg ~ "\n" ~ exp); 319 } 320 321 /// ditto 322 unittest { 323 struct Foo { 324 bool empty; 325 int front(); 326 } 327 enum msg = isBidirectionalRangeErrorFormatter!(Foo); 328 enum exp =`Foo is not an BidirectionalRange because 329 the function 'popFront' does not exist 330 and the property 'back' does not exist 331 and the function 'popBack' does not exist`; 332 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 333 string msg2 = isBidirectionalRangeErrorFormatter!(Foo); 334 assert(msg2 == exp, msg ~ "\n" ~ exp); 335 } 336 337 /// ditto 338 unittest { 339 struct Foo { 340 bool empty; 341 int front(); 342 void popFront(); 343 float back(); 344 } 345 enum msg = isBidirectionalRangeErrorFormatter!(Foo); 346 enum exp =`Foo is not an BidirectionalRange because 347 the property 'back' does return a 'float' which is not equal to the type of 'front' which is 'int' 348 and the function 'popBack' does not exist`; 349 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 350 string msg2 = isBidirectionalRangeErrorFormatter!(Foo); 351 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 352 } 353 354 /// ditto 355 unittest { 356 struct Foo { 357 bool empty; 358 int front(); 359 void popFront(); 360 float back(); 361 } 362 enum msg = isBidirectionalRangeErrorFormatter!(Foo); 363 enum exp =`Foo is not an BidirectionalRange because 364 the property 'back' does return a 'float' which is not equal to the type of 'front' which is 'int' 365 and the function 'popBack' does not exist`; 366 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 367 string msg2 = isBidirectionalRangeErrorFormatter!(Foo); 368 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 369 } 370 371 /// ditto 372 unittest { 373 struct Foo { 374 bool empty; 375 int front(); 376 void popFront(); 377 int back(); 378 379 } 380 enum msg = isBidirectionalRangeErrorFormatter!(Foo); 381 enum exp =`Foo is not an BidirectionalRange because 382 the function 'popBack' does not exist`; 383 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 384 string msg2 = isBidirectionalRangeErrorFormatter!(Foo); 385 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 386 } 387 388 /// ditto 389 unittest { 390 struct Foo { 391 bool empty; 392 int front(); 393 void popFront(); 394 int back(); 395 void popBack(); 396 397 } 398 enum msg = isBidirectionalRangeErrorFormatter!(Foo); 399 static assert(msg == "Foo is an BidirectionalRange", msg); 400 string msg2 = isBidirectionalRangeErrorFormatter!(Foo); 401 assert(msg2 == "Foo is an BidirectionalRange", msg); 402 } 403 404 /** 405 * This function produces a descriptive message why `R` is not a 406 * RandomAccessRange. 407 * If `R` is an RandomAccessRange the returned string will say so. 408 */ 409 string isRandomAccessRangeErrorFormatter(R)() pure { 410 static if(is(typeof(R.init) == R)) { 411 string ret = R.stringof ~ " is not an RandomAccessRange because\n\t"; 412 413 static if(!(isBidirectionalRange!R || !isInfinite!R)) { 414 Test isNotBiNorInf = Test(true 415 , ".empty' must either be 'enum bool = " 416 ~ "true' or 'ReturnType!(" ~ R.stringof ~ ".back)' must be equal" 417 ~ " to 'ReturnType!(" ~ R.stringof ~ ".front)'"); 418 } else { 419 Test isNotBiNorInf = Test(false, ""); 420 } 421 422 static if(!(hasLength!R || !isInfinite!R)) { 423 Test hasLenOrInf = Test(true 424 , ".empty' must either be 'enum bool = " 425 ~ "true' or '" ~ R.stringof 426 ~ ".length' must be of type 'size_t'"); 427 } else { 428 Test hasLenOrInf = Test(false, ""); 429 } 430 431 static if(!is(typeof(lvalueOf!R[1]))) { 432 Test allowOpIndex = Test(true 433 , "must allow for array indexing, aka. [] access"); 434 } else { 435 Test allowOpIndex = Test(false, ""); 436 } 437 438 static if(is(typeof(lvalueOf!R[1])) 439 && !is(typeof(lvalueOf!R[1]) == ElementType!R)) 440 { 441 Test opIndexType = Test(true 442 , R.stringof ~ "[1] is of type '" 443 ~ typeof(lvalueOf!R[1]) ~ "' but must be equal to '" 444 ~ R.stringof ~ ".front' which is '" ~ ElementType!(R).stringof 445 ~ "'"); 446 } else { 447 Test opIndexType = Test(false, ""); 448 } 449 450 Test[] tests = 451 [ isValidEmpty!R() 452 , isFrontValid!R() 453 , isPopFrontValid!R() 454 , isSaveValid!R() 455 , isNotSomeString!R() 456 , isNotBiNorInf 457 , hasLenOrInf 458 , allowOpIndex 459 , opIndexType 460 ]; 461 462 auto msg = testsToString(tests); 463 464 bool failed = tests.map!(t => t.failed).any(); 465 466 return failed 467 ? ret ~ msg 468 : R.stringof ~ " is an RandomAccessRange"; 469 } else { 470 return R.stringof ~ " can not be tested as " ~ R.stringof ~ ".init" 471 ~ " does not construct a compileable " ~ R.stringof; 472 } 473 } 474 475 /// ditto 476 unittest { 477 struct Foo {} 478 enum msg = isRandomAccessRangeErrorFormatter!(Foo); 479 enum exp =`Foo is not an RandomAccessRange because 480 the property 'empty' does not exist 481 and the property 'front' does not exist 482 and the function 'popFront' does not exist 483 and the property 'save' does not exist 484 and must allow for array indexing, aka. [] access`; 485 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 486 string msg2 = isRandomAccessRangeErrorFormatter!(Foo); 487 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 488 } 489 490 /// ditto 491 unittest { 492 struct Foo { 493 int empty; 494 } 495 enum msg = isRandomAccessRangeErrorFormatter!(Foo); 496 enum exp = `Foo is not an RandomAccessRange because 497 the property 'empty' is not of type 'bool' but 'int' 498 and the property 'front' does not exist 499 and the function 'popFront' does not exist 500 and the property 'save' does not exist 501 and must allow for array indexing, aka. [] access`; 502 static assert(msg == exp, msg ~ "\n" ~ exp); 503 string msg2 = isRandomAccessRangeErrorFormatter!(Foo); 504 assert(msg2 == exp, msg ~ "\n" ~ exp); 505 } 506 507 /// ditto 508 unittest { 509 struct Foo { 510 bool empty; 511 void front(); 512 } 513 enum msg = isRandomAccessRangeErrorFormatter!(Foo); 514 enum exp =`Foo is not an RandomAccessRange because 515 the property 'front' does not return a non 'void' value 516 and the function 'popFront' does not exist 517 and the property 'save' does not exist 518 and must allow for array indexing, aka. [] access`; 519 static assert(msg == exp, msg ~ "\n" ~ exp); 520 string msg2 = isRandomAccessRangeErrorFormatter!(Foo); 521 assert(msg2 == exp, msg ~ "\n" ~ exp); 522 } 523 524 /// ditto 525 unittest { 526 struct Foo { 527 bool empty; 528 int front(); 529 } 530 enum msg = isRandomAccessRangeErrorFormatter!(Foo); 531 enum exp =`Foo is not an RandomAccessRange because 532 the function 'popFront' does not exist 533 and the property 'save' does not exist 534 and must allow for array indexing, aka. [] access`; 535 static assert(msg == exp, msg ~ "\n" ~ exp); 536 string msg2 = isRandomAccessRangeErrorFormatter!(Foo); 537 assert(msg2 == exp, msg ~ "\n" ~ exp); 538 } 539 540 /// ditto 541 unittest { 542 struct Foo { 543 bool empty; 544 int front(); 545 void popFront(); 546 float back(); 547 } 548 enum msg = isRandomAccessRangeErrorFormatter!(Foo); 549 enum exp =`Foo is not an RandomAccessRange because 550 the property 'save' does not exist 551 and must allow for array indexing, aka. [] access`; 552 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 553 string msg2 = isRandomAccessRangeErrorFormatter!(Foo); 554 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 555 } 556 557 /// ditto 558 unittest { 559 struct Foo { 560 enum empty = true; 561 int front(); 562 void popFront(); 563 float back(); 564 } 565 enum msg = isRandomAccessRangeErrorFormatter!(Foo); 566 enum exp =`Foo is not an RandomAccessRange because 567 the property 'save' does not exist 568 and must allow for array indexing, aka. [] access`; 569 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 570 string msg2 = isRandomAccessRangeErrorFormatter!(Foo); 571 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 572 } 573 574 /// ditto 575 unittest { 576 struct Foo { 577 enum empty = true; 578 int front(); 579 void popFront(); 580 float back(); 581 Foo save() { return this; } 582 } 583 enum msg = isRandomAccessRangeErrorFormatter!(Foo); 584 enum exp =`Foo is not an RandomAccessRange because 585 must allow for array indexing, aka. [] access`; 586 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 587 string msg2 = isRandomAccessRangeErrorFormatter!(Foo); 588 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 589 } 590 591 /// ditto 592 unittest { 593 struct Foo { 594 enum empty = true; 595 int front(); 596 void popFront(); 597 float back(); 598 Foo save() { return this; } 599 int opIndex(size_t idx) { return 0; } 600 size_t length() { return 0; } 601 } 602 enum msg = isRandomAccessRangeErrorFormatter!(Foo); 603 enum exp =`Foo is an RandomAccessRange`; 604 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 605 string msg2 = isRandomAccessRangeErrorFormatter!(Foo); 606 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 607 } 608 609 /** 610 * This function produces a descriptive message why `R` is not an 611 * OutputRange. 612 * If `R` is an OutputRange the returned string will say so. 613 */ 614 string isOutputRangeErrorFormatter(R,E)() pure { 615 string ret = R.stringof ~ " is not an OutputRange because"; 616 617 Test putTest = isOutputRangeValue!(R,E)(); 618 619 return putTest.failed 620 ? ret ~ "\n\t" ~ putTest.message 621 : R.stringof ~ " is an OutputRange"; 622 } 623 624 unittest { 625 struct Foo {} 626 enum msg = isOutputRangeErrorFormatter!(Foo,int); 627 enum exp =`Foo is not an OutputRange because 628 calling std.range.primitives.put(ref Foo, int) is not possible`; 629 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 630 string msg2 = isOutputRangeErrorFormatter!(Foo,int); 631 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 632 } 633 634 unittest { 635 struct Foo { 636 void put(int a) { } 637 } 638 enum msg = isOutputRangeErrorFormatter!(Foo,int); 639 enum exp =`Foo is an OutputRange`; 640 static assert(msg == exp, "\n" ~ msg ~ "\n" ~ exp); 641 string msg2 = isOutputRangeErrorFormatter!(Foo,int); 642 assert(msg2 == exp, "\n" ~ msg ~ "\n" ~ exp); 643 } 644 645 private: 646 647 struct Test { 648 bool failed; 649 string message; 650 } 651 652 // 653 // isFrontValid 654 // 655 Test isFrontValid(R)() { 656 enum hasFront = is(typeof((return ref R r) => r.front)); 657 static if(hasFront) { 658 alias RTfront = ReturnType!((R r) => r.front); 659 enum hasFrontIsVoid = is(RTfront == void); 660 static if(hasFrontIsVoid) { 661 return Test(true 662 , "the property 'front' does not return a non 'void' " 663 ~ "value"); 664 } else { 665 return Test(false, ""); 666 } 667 } else { 668 return Test(true, "the property 'front' does not exist"); 669 } 670 } 671 672 unittest { 673 struct Foo{} 674 enum Test a = isFrontValid!Foo(); 675 static assert(a.failed); 676 static assert(a.message == "the property 'front' does not exist" 677 , a.message); 678 } 679 680 unittest { 681 struct Foo{ 682 int front; 683 } 684 enum Test a = isFrontValid!Foo(); 685 static assert(!a.failed); 686 static assert(a.message.empty, a.message); 687 } 688 689 // 690 // isBackValid 691 // 692 Test isBackValid(R)() { 693 enum hasBack = is(typeof((return ref R r) => r.back)); 694 static if(hasBack) { 695 alias RTback = ReturnType!((R r) => r.back); 696 enum hasBackIsEqualToFront = is(RTback == ElementType!R); 697 static if(!hasBackIsEqualToFront) { 698 return Test(true 699 , "the property 'back' does return a '" ~ RTback.stringof 700 ~ "' which is not equal to the type of 'front' which is '" 701 ~ ElementType!(R).stringof ~ "'"); 702 } else { 703 return Test(false, ""); 704 } 705 } else { 706 return Test(true, "the property 'back' does not exist"); 707 } 708 } 709 710 unittest { 711 struct Foo{} 712 enum Test a = isBackValid!Foo(); 713 static assert(a.failed); 714 static assert(a.message == "the property 'back' does not exist" 715 , a.message); 716 } 717 718 unittest { 719 struct Foo{ 720 int back; 721 } 722 enum Test a = isBackValid!Foo(); 723 static assert(a.failed); 724 static assert(a.message == "the property 'back' does return a 'int' which is not equal to the type of 'front' which is 'void'" 725 , a.message); 726 } 727 728 unittest { 729 struct Foo{ 730 int back; 731 double front; 732 } 733 enum Test a = isBackValid!Foo(); 734 static assert(a.failed); 735 static assert(a.message == "the property 'back' does return a 'int' which is not equal to the type of 'front' which is 'double'" 736 , a.message); 737 } 738 739 unittest { 740 struct Foo{ 741 int back; 742 int front; 743 } 744 enum Test a = isBackValid!Foo(); 745 static assert(!a.failed); 746 static assert(a.message.empty, a.message); 747 } 748 749 // 750 // isPopFrontValid 751 // 752 Test isPopFrontValid(R)() { 753 enum hasPopFront = is(typeof((R r) => r.popFront)); 754 static if(!hasPopFront) { 755 return Test(true, "the function 'popFront' does not exist"); 756 } else { 757 return Test(false, ""); 758 } 759 } 760 761 unittest { 762 struct Foo{} 763 enum Test a = isPopFrontValid!Foo(); 764 static assert(a.failed); 765 static assert(a.message == "the function 'popFront' does not exist" 766 , a.message); 767 } 768 769 unittest { 770 struct Foo{ 771 void popFront(); 772 } 773 enum Test a = isPopFrontValid!Foo(); 774 static assert(!a.failed); 775 static assert(a.message.empty); 776 } 777 778 // 779 // isPopBackValid 780 // 781 Test isPopBackValid(R)() { 782 enum hasPopBack = is(typeof((R r) => r.popBack)); 783 static if(!hasPopBack) { 784 return Test(true, "the function 'popBack' does not exist"); 785 } else { 786 return Test(false, ""); 787 } 788 } 789 790 unittest { 791 struct Foo{} 792 enum Test a = isPopBackValid!Foo(); 793 static assert(a.failed); 794 static assert(a.message == "the function 'popBack' does not exist" 795 , a.message); 796 } 797 798 unittest { 799 struct Foo{ 800 void popBack(); 801 } 802 enum Test a = isPopBackValid!Foo(); 803 static assert(!a.failed); 804 static assert(a.message.empty); 805 } 806 807 // 808 // isSaveValid 809 // 810 Test isSaveValid(R)() { 811 enum hasSave = is(typeof((R r) => r.save)); 812 static if(hasSave) { 813 alias RTsave = ReturnType!((R r) => r.save); 814 enum isSaveR = is(RTsave == R); 815 static if(!isSaveR) { 816 return Test(true, 817 "the property 'save' does not return a '" ~ R.stringof 818 ~ "' but a '" ~ RTsave.stringof ~ "'"); 819 } else { 820 return Test(false, ""); 821 } 822 } else { 823 return Test(true, "the property 'save' does not exist"); 824 } 825 } 826 827 unittest { 828 struct Foo{} 829 enum Test a = isSaveValid!Foo(); 830 static assert(a.failed); 831 static assert(a.message == "the property 'save' does not exist"); 832 } 833 834 unittest { 835 struct Foo{ 836 int save; 837 } 838 enum Test a = isSaveValid!Foo(); 839 static assert(a.failed); 840 static assert(a.message == "the property 'save' does not return a 'Foo'" 841 ~ " but a 'int'"); 842 } 843 844 // 845 // isValidEmpty 846 // 847 Test isValidEmpty(R)() { 848 enum hasEmpty = __traits(hasMember, R, "empty"); 849 static if(hasEmpty) { 850 static if (__traits(compiles, { enum e = R.empty; })) { 851 enum bool b = R.empty; 852 static if(b) { 853 return Test(R.empty == false, ""); 854 } else { 855 return Test(true, "the enum 'empty' must not be 'false'"); 856 } 857 } else if(is(typeof(__traits(getMember, R, "empty")) == bool)) { 858 return Test(false, ""); 859 } else { 860 return Test(true, "the property 'empty' is not of type 'bool' but '" 861 ~ typeof(R.empty).stringof ~ "'"); 862 } 863 } else { 864 return Test(true, "the property 'empty' does not exist"); 865 } 866 } 867 868 unittest { 869 struct Foo {} 870 enum Test a = isValidEmpty!Foo(); 871 static assert(a.failed); 872 static assert(a.message == "the property 'empty' does not exist" 873 , a.message); 874 } 875 876 unittest { 877 struct Foo { 878 int empty; 879 } 880 enum Test a = isValidEmpty!Foo(); 881 static assert(a.failed); 882 static assert(a.message == 883 "the property 'empty' is not of type 'bool' but 'int'" 884 , a.message); 885 } 886 887 unittest { 888 struct Foo { 889 enum bool empty = false; 890 } 891 enum Test a = isValidEmpty!Foo(); 892 static assert(a.failed); 893 static assert(a.message == "the enum 'empty' must not be 'false'" 894 , a.message); 895 } 896 897 unittest { 898 struct Foo { 899 bool empty; 900 } 901 enum Test a = isValidEmpty!Foo(); 902 static assert(!a.failed); 903 static assert(a.message.empty); 904 } 905 906 unittest { 907 struct Foo { 908 enum bool empty = true; 909 } 910 enum Test a = isValidEmpty!Foo(); 911 static assert(!a.failed, a.message); 912 static assert(a.message.empty); 913 } 914 915 // 916 // isValidBoolEnum 917 // 918 Test isValidBoolEnum(R)() { 919 static if (__traits(compiles, { enum e = R.empty; })) { 920 enum bool b = R.empty; 921 static if(b) { 922 return Test(R.empty == false, ""); 923 } else { 924 return Test(true, "the enum 'empty = true' must not be 'false'"); 925 } 926 } else { 927 return Test(true, "the enum 'empty = true' does not exist"); 928 } 929 } 930 931 unittest { 932 struct Foo {} 933 enum Test a = isValidBoolEnum!Foo(); 934 static assert(a.failed); 935 static assert(a.message == "the enum 'empty = true' does not exist" 936 , a.message); 937 } 938 939 unittest { 940 struct Foo { 941 int empty; 942 } 943 enum Test a = isValidBoolEnum!Foo(); 944 static assert(a.failed); 945 static assert(a.message == "the enum 'empty = true' does not exist" 946 , a.message); 947 } 948 949 unittest { 950 struct Foo { 951 enum bool empty = false; 952 } 953 enum Test a = isValidBoolEnum!Foo(); 954 static assert(a.failed); 955 static assert(a.message == "the enum 'empty = true' must not be 'false'" 956 , a.message); 957 } 958 959 unittest { 960 struct Foo { 961 bool empty; 962 } 963 enum Test a = isValidBoolEnum!Foo(); 964 static assert(a.failed); 965 static assert(a.message == "the enum 'empty = true' does not exist" 966 , a.message); 967 } 968 969 unittest { 970 struct Foo { 971 enum bool empty = true; 972 } 973 enum Test a = isValidBoolEnum!Foo(); 974 static assert(!a.failed, a.message); 975 static assert(a.message.empty); 976 } 977 978 // 979 // isValidOpIndex 980 // 981 Test isValidOpIndex(R)() { 982 static if(!is(typeof(lvalueOf!R[1]))) { 983 return Test(true, "[] aka. opIndex not possible"); 984 } else static if(is(typeof(lvalueOf!R[1])) 985 && !is(typeof(lvalueOf!R[1]) == ElementType!R)) 986 { 987 return Test(true 988 , R.stringof ~ "[idx] is of type '" 989 ~ typeof(lvalueOf!R[1]).stringof ~ "' but must be equal to '" 990 ~ R.stringof ~ ".front' which is '" ~ ElementType!(R).stringof 991 ~ "'"); 992 } else { 993 return Test(false, ""); 994 } 995 } 996 997 unittest { 998 struct Foo {} 999 enum Test a = isValidOpIndex!Foo(); 1000 static assert(a.failed); 1001 static assert(a.message == "[] aka. opIndex not possible", a.message); 1002 } 1003 1004 unittest { 1005 struct Foo { 1006 int opIndex(size_t i) { assert(false); } 1007 } 1008 enum Test a = isValidOpIndex!Foo(); 1009 static assert(a.failed); 1010 static assert(a.message == "Foo[idx] is of type 'int' but must be equal to 'Foo.front' which is 'void'"); 1011 } 1012 1013 unittest { 1014 struct Foo { 1015 double front; 1016 int opIndex(size_t i) { assert(false); } 1017 } 1018 enum Test a = isValidOpIndex!Foo(); 1019 static assert(a.failed); 1020 static assert(a.message == "Foo[idx] is of type 'int' but must be equal to 'Foo.front' which is 'double'"); 1021 } 1022 1023 unittest { 1024 struct Foo { 1025 int front; 1026 int opIndex(size_t i) { assert(false); } 1027 } 1028 enum Test a = isValidOpIndex!Foo(); 1029 static assert(!a.failed); 1030 static assert(a.message); 1031 } 1032 1033 // 1034 // hasValidLength 1035 // 1036 Test hasValidLength(R)() { 1037 static if(hasLength!R) { 1038 return Test(false, ""); 1039 } else { 1040 return Test(true, "property 'size_t length' is not defined"); 1041 } 1042 } 1043 1044 unittest { 1045 struct Foo {} 1046 enum Test a = hasValidLength!Foo(); 1047 static assert(a.failed); 1048 static assert(a.message == "property 'size_t length' is not defined" 1049 , a.message); 1050 } 1051 1052 unittest { 1053 struct Foo { 1054 double length; 1055 } 1056 enum Test a = hasValidLength!Foo(); 1057 static assert(a.failed); 1058 static assert(a.message == "property 'size_t length' is not defined" 1059 , a.message); 1060 } 1061 1062 unittest { 1063 struct Foo { 1064 size_t length; 1065 } 1066 enum Test a = hasValidLength!Foo(); 1067 static assert(!a.failed); 1068 static assert(a.message.empty); 1069 } 1070 1071 // 1072 // isNotSomeString 1073 // 1074 Test isNotSomeString(R)() { 1075 static if(isAutodecodableString!R || !isAggregateType!R) { 1076 return Test(true, R.stringof ~ " must not be an autodecodable string" 1077 ~ " but should be an aggregate type"); 1078 } else { 1079 return Test(false, ""); 1080 } 1081 } 1082 1083 // 1084 // isValidOutputRange 1085 // 1086 Test isOutputRangeValue(R, E)() { 1087 static if(!is(typeof(put(lvalueOf!R, lvalueOf!E)))) { 1088 return Test(true, "calling std.range.primitives.put(ref " ~ R.stringof 1089 ~ ", " ~ E.stringof ~ ") is not possible"); 1090 } else { 1091 return Test(false, ""); 1092 } 1093 } 1094 1095 // 1096 // helper 1097 // 1098 1099 string testsToString(Test[] tests) pure { 1100 return tests 1101 .filter!(t => t.failed) 1102 .map!(t => t.message) 1103 .joiner("\n\tand ") 1104 .to!string(); 1105 } 1106 1107 void doPutCopyPast(R, E)(ref R r, auto ref E e) 1108 { 1109 static if (is(PointerTarget!R == struct)) 1110 enum usingPut = hasMember!(PointerTarget!R, "put"); 1111 else 1112 enum usingPut = hasMember!(R, "put"); 1113 1114 static if (usingPut) 1115 { 1116 static assert(is(typeof(r.put(e))), 1117 "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); 1118 r.put(e); 1119 } 1120 else static if (isNarrowString!R && is(const(E) == const(typeof(r[0])))) 1121 { 1122 // one character, we can put it 1123 r[0] = e; 1124 r = r[1 .. $]; 1125 } 1126 else static if (isNarrowString!R && isNarrowString!E && is(typeof(r[] = e))) 1127 { 1128 // slice assign. Note that this is a duplicate from put, but because 1129 // putChar uses doPut exclusively, we have to copy it here. 1130 immutable len = e.length; 1131 r[0 .. len] = e; 1132 r = r[len .. $]; 1133 } 1134 else static if (isInputRange!R) 1135 { 1136 static assert(is(typeof(r.front = e)), 1137 "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); 1138 r.front = e; 1139 r.popFront(); 1140 } 1141 else static if (is(typeof(r(e)))) 1142 { 1143 r(e); 1144 } 1145 else 1146 { 1147 static assert(false, 1148 "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); 1149 } 1150 }